﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using AdaptiveAgents.Agents;
using AdaptiveAgents.Games;
using AdaptiveAgents.Distributions;
using AdaptiveAgents.Running_Tools;
using AdaptiveAgents.Tools;


namespace AdaptiveAgents.Experiments
{
    class NormalNAgentExperiment : Experiment
    {

        //data members
        public List<double> EpsilonData { get; private set; }
        public List<double> CompetenceData { get; private set; }
        private int _Rounds;
        private int _Agents;
        private int _Games;
        private string _GameType;
        private string _EnvironmentType;
        private string _FilePath;
        private List<AgentInput> _AgentDataList;
        private DataTable _DataTable;
        
        /// <summary>
        /// Constructor - 
        /// </summary>
        public NormalNAgentExperiment(ExperimentEntry entry) : base(entry.ROUNDS,entry.AGENTS,entry.GAMES)
        {
            _Agents = entry.AGENTS;
            _Games = entry.GAMES;
            _Rounds = entry.ROUNDS;
            _GameType = entry.GAME_TYPE;
            _EnvironmentType = entry.ENVIRONMENT_TYPE;
            _FilePath = entry.FILE_PATH;
            _AgentDataList = entry.LIST;
        }
              

        /// <summary>
        /// run the experiment
        /// </summary>
        public override void runExperiment()
        {

            EpsilonData = new List<double>();
            CompetenceData = new List<double>();
            //create a DataTable for MDPDiscover agent's data and set its rows

            _DataTable = ProcessorData.CreateFullDataTable(Strategist.craeteDataBaseTitle(_GameType), NumAgents, _Rounds); 

            //run games
            for (int i = 0; i < _Games; ++i)
            {             
                for(int j = 0; j< NumAgents; j++)
                {
                    EpsilonData.Add(_AgentDataList[j].Epsilon);
                    CompetenceData.Add(_AgentDataList[j].Competence);
                }          

                //write to console to see progress
                
                System.Console.WriteLine("Game Number: " + (i+1));

                RunGame(_DataTable, i, _GameType); 
            }

            //create file names and write to the files
            String stamp = DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss");
            CSVprinter.WriteToCSV("Full Data Of " + Strategist.craeteDataBaseTitle(_GameType) + stamp + ".csv", _DataTable);
            DataTable averageDataTable = ProcessorData.CreateAverageDateTable(Strategist.craeteDataBaseTitle(_GameType),_DataTable,_Games,_Rounds,_Agents);
            CSVprinter.WriteToCSV("Average Data Of " + Strategist.craeteDataBaseTitle(_GameType) + stamp + ".csv", averageDataTable);
        }       

        /// <summary>
        /// Run a dingle game
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="dt"></param>
        /// <param name="gameNum"></param>
        protected void RunGame(DataTable dt, int gameNum, string gameType)
        {
            // first let's set the environment
            Environment environment = new Environment();
            DataRow row = DataRowProcessor.createDataRow(dt);

            DataRowProcessor.insertNumberGame(gameNum);
            DataRowProcessor.insertEpsilonsData(EpsilonData, _Agents);
            DataRowProcessor.insertCompetenceData(CompetenceData,_Agents);

        

            //Create a new population of players
            //The agentType is MDPDiscovery so we create a MDPDiscovery agent and two normal agents
            List<Agent> agents = Strategist.createAgentsList(environment, _AgentDataList, EpsilonData, CompetenceData, _logger);

            //List<Agent> agents = generatePlayers(environment, builder);

            for (int j = 0; j < NumAgents; j++)
            {
                Agent agent = agents[j];
                environment.addAgent(agent);
            }

            //create a game
            MDPGame game = (MDPGame)Strategist.createGame(gameType, environment, _Rounds);

            double utility = 0;

            //set the agents with their Competence
            for (int j = 0; j < NumAgents; j++)
            {
                environment.agents[j].Competence = new Blocks(CompetenceData[j]);
            }

            //enter to the game the row it needs to write the game data to
            game.Dr1 = row;

            //run the game and get back the utility of the game
            utility = game.start(_logger);

            //update utility
            DataRowProcessor.insertAverageScore(utility);

            //total sum
            DataRowProcessor.insertSumScore(game);
            DataRowProcessor.insertMinMaxScore(_Rounds);
            DataRowProcessor.insertAverageScorePerAgente(environment,_Rounds);

            //add the game data to the DataTable
            dt.Rows.Add(row);
        }

      
       }
}
